﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using UIT.Controls.Containers;
using UIT.Controls.Data;
using UIT.Controls.Data.Parameters;
using UIT.Controls;
using System.Collections;

namespace UIT
{
	public interface IDisposableObservableCollection<out TParent, TChild> : ICollection<TChild>, INotifyCollectionChanged, IDisposable, IList
		where TChild : IContainable<TParent>, IDisposable
	{ int IndexOf(TChild control);}

	public class ParameterCollection : DisposableObservableCollection<IDataProvider, IParameter>
	{
		public ParameterCollection(IDataProvider parent)
			: base(parent)
		{

		}
	}

	public class SingleControlCollection<TContainer, TControl> : SingleItemDisposableObservableCollection<TContainer, TControl>
		where TContainer : IContainer
		where TControl : IControl, IContainable<TContainer>
	{
		public SingleControlCollection(TContainer parent)
			: base(parent)
		{

		}
	}

	public class ControlCollection<TContainer, TControl> : DisposableObservableCollection<TContainer, TControl>
		where TContainer : IContainer
		where TControl : IControl, IContainable<TContainer>
	{
		public ControlCollection(TContainer parent)
			: base(parent)
		{

		}
	}

	public class SingleControlCollection<TControl> : SingleControlCollection<IContainer, TControl>
		where TControl : IControl, IContainable<IContainer>
	{
		public SingleControlCollection(IContainer parent)
			: base(parent)
		{

		}
	}

	public class ControlCollection<TControl> : ControlCollection<IContainer, TControl>
		where TControl : IControl, IContainable<IContainer>
	{
		public ControlCollection(IContainer parent)
			: base(parent)
		{

		}
	}

	public class SingleControlCollection : SingleControlCollection<IControl>
	{
		public SingleControlCollection(IContainer parent)
			: base(parent)
		{

		}
	}

	public class ControlCollection : ControlCollection<IControl>
	{
		public ControlCollection(IContainer parent)
			: base(parent)
		{

		}
	}

	public class SingleItemDisposableObservableCollection<TParent, TChild> : IDisposableObservableCollection<TParent, TChild>
		where TChild : IContainable<TParent>, IDisposable
	{
		private TParent parent;
		private TChild child;

		public TChild Child { get { return child; } }

		public SingleItemDisposableObservableCollection(TParent parent)
		{
			this.parent = parent;

		}

		#region ICollection<TChild> Members

		public void Add(TChild item)
		{
			if (EqualityComparer<TChild>.Default.Equals(processingItem, item))
				return;
			processingItem = item;
			child = item;
			if (child != null)
				child.Parent = parent;
			if (CollectionChanged != null)
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, 0));
			processingItem = default(TChild);
		}

		public void Clear()
		{
			if (CollectionChanged != null)
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
			child = default(TChild);
		}

		public bool Contains(TChild item)
		{
			return EqualityComparer<TChild>.Default.Equals(child, item);
		}

		public void CopyTo(TChild[] array, int arrayIndex)
		{
			if (child != null)
				array[arrayIndex] = child;
		}

		public int Count
		{
			get { return Contains(default(TChild)) ? 0 : 1; }
		}

		public bool IsReadOnly
		{
			get { return false; }
		}

		public bool Remove(TChild item)
		{
			if (Contains(item))
			{
				child = default(TChild);
				if (CollectionChanged != null)
					CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, 0));
				return true;
			}
			return false;
		}

		#endregion

		#region IEnumerable<TChild> Members

		public IEnumerator<TChild> GetEnumerator()
		{
			yield return child;
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#endregion

		#region INotifyCollectionChanged Members

		public event NotifyCollectionChangedEventHandler CollectionChanged;
		private TChild processingItem;

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			if (child != null)
				child.Dispose();
			CollectionChanged = null;
			child = default(TChild);
		}

		#endregion

		#region IDisposableObservableCollection<TParent,TChild> Members

		public int IndexOf(TChild control)
		{
			if (Contains(control))
				return 0;
			return -1;
		}

		#endregion

		int IList.Add(object value)
		{
			Add((TChild)value);
			return 1;
		}

		bool IList.Contains(object value)
		{
			return Contains((TChild)value);
		}

		int IList.IndexOf(object value)
		{
			return IndexOf((TChild)value);
		}

		void IList.Insert(int index, object value)
		{
			throw new NotSupportedException();
		}

		bool IList.IsFixedSize
		{
			get { return true; }
		}

		void IList.Remove(object value)
		{
			Remove((TChild)value);
		}

		void IList.RemoveAt(int index)
		{
			throw new NotSupportedException();
		}

		object IList.this[int index]
		{
			get
			{
				if (index == 0)
					return child;
				throw new IndexOutOfRangeException();
			}
			set
			{
				if (index == 0)
					((IList)this).Add(value);
				throw new IndexOutOfRangeException();
			}
		}

		void ICollection.CopyTo(Array array, int index)
		{
			if (child != null)
				array.SetValue(child, index);
		}

		bool ICollection.IsSynchronized
		{
			get { return false; }
		}

		object ICollection.SyncRoot
		{
			get { return null; }
		}
	}

	public class DisposableObservableCollection<TParent, TChild> : IDisposableObservableCollection<TParent, TChild>
		where TChild : IContainable<TParent>, IDisposable
	{
		public DisposableObservableCollection(TParent parent)
		{
			this.parent = parent;
			innerList = new List<TChild>();
		}

		TChild currentItemHandled;

		#region ICollection<TChild> Members

		public void Add(TChild item)
		{
			if (object.ReferenceEquals(currentItemHandled, item))
				return;
			currentItemHandled = item;
			item.Parent = parent;
			innerList.Add(item);
			if (CollectionChanged != null)
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, innerList.Count - 1));
			currentItemHandled = default(TChild);
		}

		public void Clear()
		{
			foreach (var item in innerList)
			{
				currentItemHandled = item;
				item.Parent = default(TParent);
			}
			currentItemHandled = default(TChild);
			innerList.Clear();
			if (CollectionChanged != null)
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}

		public bool Contains(TChild item)
		{
			return innerList.Contains(item);
		}

		public void CopyTo(TChild[] array, int arrayIndex)
		{
			innerList.CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get { return innerList.Count; }
		}

		public bool IsReadOnly
		{
			get { return innerList.IsReadOnly; }
		}

		public bool Remove(TChild item)
		{
			if (object.ReferenceEquals(currentItemHandled, item))
				return false;
			currentItemHandled = item;
			if (innerList.Remove(item))
			{
				if (CollectionChanged != null)
					CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, -1));
				return true;
			}
			return false;
		}

		#endregion

		#region IEnumerable<TChild> Members

		public IEnumerator<TChild> GetEnumerator()
		{
			return innerList.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return innerList.GetEnumerator();
		}

		#endregion

		#region INotifyCollectionChanged Members

		public event NotifyCollectionChangedEventHandler CollectionChanged;
		private TParent parent;
		private IList<TChild> innerList;

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			foreach (var item in innerList)
			{
				currentItemHandled = item;
				item.Parent = default(TParent);
				item.Dispose();
			}

			currentItemHandled = default(TChild);
			innerList = null;
			parent = default(TParent);
		}

		#endregion

		#region IDisposableObservableCollection<TParent,TChild> Members

		public int IndexOf(TChild control)
		{
			return innerList.IndexOf(control);
		}

		#endregion

		int IList.Add(object value)
		{
			Add((TChild)value);
			return 1;
		}

		bool IList.Contains(object value)
		{
			return Contains((TChild)value);
		}

		int IList.IndexOf(object value)
		{
			return IndexOf((TChild)value);
		}

		void IList.Insert(int index, object value)
		{
			TChild item = (TChild)value;
			if (object.ReferenceEquals(currentItemHandled, item))
				return;
			currentItemHandled = item;
			item.Parent = parent;
			innerList.Insert(index, item);
			if (CollectionChanged != null)
				CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
			currentItemHandled = default(TChild);

		}

		bool IList.IsFixedSize
		{
			get { return ((IList)innerList).IsFixedSize; }
		}

		void IList.Remove(object value)
		{
			Remove((TChild)value);
		}

		void IList.RemoveAt(int index)
		{
			TChild item = innerList[index];
			if (object.ReferenceEquals(currentItemHandled, item))
				return;
			currentItemHandled = item;
			if (innerList.Remove(item))
			{
				if (CollectionChanged != null)
					CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index));
				return;
			}
		}

		object IList.this[int index]
		{
			get
			{
				return innerList[index];
			}
			set
			{
				innerList[index] = (TChild)value;
			}
		}

		void ICollection.CopyTo(Array array, int index)
		{
			((IList)innerList).CopyTo(array, index);
		}

		bool ICollection.IsSynchronized
		{
			get { return ((IList)innerList).IsSynchronized; }
		}

		object ICollection.SyncRoot
		{
			get { return ((IList)innerList).SyncRoot; }
		}
	}
}
